﻿using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace HXu.BaseTools
{
    /// <summary>
    /// MathTools 数学工具 <br />
    /// /************************************************* <br />
    /// -- 内容：<br />
    ///     1A、链表对象 是否 为空链表 或 元素个数为0。<br />
    ///     1B、字典对象 是否 为空字典 或 元素个数为0。<br />
    ///     1C、float 类型对象 是否 为0。<br />
    ///     1D、int 类型对象 是否 为0。<br />
    ///     1E、比较两个float值是否相同（利用Mathf.Epsilon）。<br />
    /// <br />     
    ///     2A、加法【链式模式】<br />
    ///     2B、减法【链式模式】<br />
    ///     2C、乘法【链式模式】<br />
    ///     2D、除法【链式模式】<br />
    ///     2E、次方【链式模式】<br />
    ///     2F、List 添加元素【链式模式】<br />
    ///     2G、Dictionary 添加（键，值）项【链式模式】<br />
    ///     2H、Dictionary 添加（键值对）项【链式模式】<br />
    /// <br />     
    ///     3A、int整数 相除得 float小数。<br />
    ///     3B、小数转为百分数。<br />
    ///     3C、开平方运算。<br />
    ///     3D、保留小数点后 n 位。<br />
    ///     3E、绝对值。<br />
    /// <br />
    ///     4A、获取 float链表 中位值。<br />
    ///     4B、获取 float链表 平均值。<br />
    ///     4C、获取 float链表 方差。<br />
    ///     4D、获取 float链表 标准差。<br />
    /// <br />     
    ///     5A、获取 float链表 最大值。<br />
    ///     5B、获取 float链表 第一个 最大值下标。<br />
    ///     5C、获取 float链表 最后一个 最大值下标。<br />
    ///     5D、获取 float链表 最小值。<br />
    ///     5E、获取 float链表 第一个 最小值下标。<br />
    ///     5F、获取 float链表 最后一个 最小值下标。<br />
    /// <br /> 
    ///     6A、返回 字典 值对应的 第一个索引。<br />
    ///     6B、返回 字典 值对应的 最后一个索引。<br />
    ///     6C、返回 字典 某下标 对应的 键值对。<br />
    ///     6D、返回 字典 某键对应的下标。<br />
    /// <br />     
    ///     7A、判断 链表对象元素 是否都为 目标元素。<br />
    ///     7B、返回 链表对象元素 组成的 字符串。<br />
    ///     7C、返回 指定链表对象 从开始下标到结束下标的元素组成的 新链表对象。<br />
    /// <br /> 
    ///     8A、获取两点距离。<br />
    ///     8B、弧度转角度。<br />
    ///     8C、角度转弧度。<br />
    ///     8D、求两向量夹角(角度值)。<br />
    ///     8E、获取 向量l1 在 向量l2 的投影向量。<br />
    /// <br /> 
    ///     9A、二进制 转 十进制（string-->int）。<br />
    ///     9B、二进制 转 十进制（string-->string）。<br />
    ///     9C、十进制 转 二进制（int-->string）。<br />
    ///     9D、十进制 转 二进制（string-->string）。<br />
    ///     9E、十六进制 转 十进制（string-->int）。<br />
    ///     9F、十六进制 转 十进制（string-->string）。<br />
    ///     9G、十进制 转 十六进制（Int-->string）。<br />
    ///     9G+、十进制 转 十六进制（UInt-->string）。<br />
    ///     9H、十进制 转 十六进制（string-->string）。<br />
    ///     9I、十六进制 转 二进制（string-->string）。<br />
    ///     9J、二进制 转 十六进制（string-->string）。<br />
    ///     9K、返回1byte（2位16进制）二进制转换后的某一位。<br />
    /// <br />
    ///     10A、将int值转换为枚举类型值（int --> Enum）。<br />
    /// <br />
    /// -- 使用方法：<br />
    ///      1、引用命名空间，直接调用。<br />
    /// *************************************************/ <br />
    /// </summary>
    public static class MathTools
    {
        /// <summary>
        /// 1A、链表对象 是否 为空链表 或 元素个数为0
        /// </summary>
        /// <typeparam name="T">链表类型</typeparam>
        /// <param name="tList">链表对象</param>
        /// <returns></returns>
        public static bool IsNullOrCountZero<T>(this IEnumerable<T> tList)
        {
            return (tList == null) || (!tList.Any());
        }

        /// <summary>
        /// 1B、字典对象 是否 为空字典 或 元素个数为0
        /// </summary>
        /// <typeparam name="T1">字典键类型</typeparam>
        /// <typeparam name="T2">字典值类型</typeparam>
        /// <param name="tDictionary">字典对象</param>
        /// <returns></returns>
        public static bool IsNullOrCountZero<T1, T2>(this Dictionary<T1, T2> tDictionary)
        {
            return (tDictionary == null) || (tDictionary.Count == 0);
        }

        /// <summary>
        /// 1C、float 类型对象 是否 为0
        /// </summary>
        /// <param name="num"></param>
        /// <returns></returns>
        public static bool IsZero(this float num)
        {
            return num == 0;
        }

        /// <summary>
        /// 1D、int 类型对象 是否 为0
        /// </summary>
        /// <param name="num"></param>
        /// <returns></returns>
        public static bool IsZero(this int num)
        {
            return num == 0;
        }

        /// <summary>
        ///  1E、比较两个float值是否相同（利用Mathf.Epsilon）
        /// </summary>
        /// <param name="num1"></param>
        /// <param name="num2"></param>
        /// <returns></returns>
        public static bool IsEqual(this float num1, float num2) => num1 >= num2 - Mathf.Epsilon && num1 <= num2 + Mathf.Epsilon;

        /// <summary>
        /// 2A、加法【链式模式】
        /// </summary>
        /// <param name="x">加数</param>
        /// <param name="y">加数</param>
        /// <returns>和</returns>
        public static float ChainAdd(this float x, float y) => x + y;

        /// <summary>
        /// 2B、减法【链式模式】
        /// </summary>
        /// <param name="x">被减数</param>
        /// <param name="y">减数</param>
        /// <returns>差</returns>
        public static float ChainSubtract(this float x, float y) => x - y;

        /// <summary>
        /// 2C、乘法【链式模式】
        /// </summary>
        /// <param name="x">因数1</param>
        /// <param name="y">因数2</param>
        /// <returns>积</returns>
        public static float ChainMultiply(this float x, float y) => x * y;

        /// <summary>
        /// 2D、除法【链式模式】
        /// </summary>
        /// <param name="x">被除数</param>
        /// <param name="y">除数</param>
        /// <returns>商</returns>
        public static float ChainDivide(this float x, float y)
        {
            if (y == 0)
                throw new Exception("the divisor cannot be 0");

            return x / y;
        }

        /// <summary>
        /// 2E、次方【链式模式】
        /// </summary>
        /// <param name="x">底数</param>
        /// <param name="y">指数</param>
        /// <returns>积</returns>
        public static int ChainPow(this float x, float y) => (int)Math.Pow(x, y);

        /// <summary>
        /// 2F、List 添加项【链式模式】
        /// </summary>
        /// <typeparam name="T">List 元素类型</typeparam>
        /// <param name="tList">List 对象</param>
        /// <param name="t">目标元素</param>
        /// <returns>添加元素后的List</returns>
        public static List<T> AddItem<T>(this List<T> tList, T t)
        {
            tList.Add(t);
            return tList;
        }

        /// <summary>
        /// 2G、Dictionary 添加（键，值）项【链式模式】
        /// </summary>
        /// <typeparam name="TKey">键类型</typeparam>
        /// <typeparam name="TValue">值类型</typeparam>
        /// <param name="dict">字典</param>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <returns>字典</returns>
        public static Dictionary<TKey, TValue> AddKeyValuePair<TKey, TValue>(this Dictionary<TKey, TValue> dict, TKey key, TValue value)
        {
            dict.Add(key, value);
            return dict;
        }

        /// <summary>
        /// 2H、Dictionary 添加（键值对）项【链式模式】
        /// </summary>
        /// <typeparam name="TKey">键类型</typeparam>
        /// <typeparam name="TValue">值类型</typeparam>
        /// <param name="dict">字典</param>
        /// <param name="keyValuePair">键值对</param>
        /// <returns>字典</returns>
        public static Dictionary<TKey, TValue> AddKeyValuePair<TKey, TValue>(this Dictionary<TKey, TValue> dict, KeyValuePair<TKey, TValue> keyValuePair)
        {
            dict.Add(keyValuePair.Key, keyValuePair.Value);
            return dict;
        }
        
        /// <summary>
        /// 3A、int整数 相除得 float小数
        /// </summary>
        /// <param name="x">被除数</param>
        /// <param name="y">除数</param>
        /// <returns>商</returns>
        public static float Division(this int x, int y)
        {
            if (y == 0)
                throw new Exception("the divisor cannot be 0");

            return (x * 1.0f / y * 1.0f);
        }

        /// <summary>
        /// 3B、小数转为百分数
        /// </summary>
        /// <param name="x">小数</param>
        /// <returns>百分数</returns>
        public static string ToPercentage(this float x) => x.ToString("0%");

        /// <summary>
        /// 3C、开平方运算
        /// </summary>
        /// <param name="x">被开平方数</param>
        /// <returns>开平方结果</returns>
        public static double GetSqrt(this int x)
        {
            if (x < 0)
                throw new Exception("the num to Sqrt cannot be minus");

            //如果输入为0 平方根结果为0
            if (x == 0)
                return 0;

            return Math.Sqrt(x);
        }

        /// <summary>
        /// 3D、保留小数点后 n 位
        /// </summary>
        /// <param name="x">被处理数</param>
        /// <param name="digitNum">小数点后位数</param>
        /// <returns></returns>
        public static float SetDigitNum(this float x, int digitNum = 2)
        {
            var digit = 10f.ChainPow(digitNum);
            var result = Mathf.Round(x * digit) / digit;
            return result;

        }

        /// <summary>
        /// 3E、绝对值
        /// </summary>
        /// <param name="num">被处理数</param>
        /// <returns>被处理数的绝对值</returns>
        public static float Abs(this float num) => Mathf.Abs(num);

        /// <summary>
        /// 4A、获取 float链表 的 中位值
        /// </summary>
        /// <param name="numList">float 链表</param>
        /// <returns>中位值</returns>
        public static float GetMedianNum(this List<float> numList)
        {
            if (numList.IsNullOrCountZero())
                throw new Exception("numList is null or count is 0");

            var vs = numList.ToList();

            vs.Sort();

            if (vs.Count % 2 == 0)
            {
                float number1 = vs[vs.Count / 2];
                float number2 = vs[(vs.Count / 2) - 1];
                return (number1 + number2) / 2;
            }
            else
            {
                return vs[vs.Count / 2];
            }
        }

        /// <summary>
        /// 4B、获取 float链表 的 平均值
        /// </summary>
        /// <param name="numList">float 链表</param>
        /// <returns>平均值</returns>
        public static float GetAverageNum(this List<float> numList)
        {
            if (numList.IsNullOrCountZero())
                throw new Exception("numList is null or count is 0");

            return numList.Average();
        }

        /// <summary>
        /// 4C、获取 float链表 的 方差
        /// </summary>
        /// <param name="numList">float 链表</param>
        /// <returns>方差</returns>
        public static float GetVarianceNum(this List<float> numList)
        {
            if (numList.IsNullOrCountZero())
                throw new Exception("numList is null or count is 0");

            var averageNum = numList.GetAverageNum();

            var varianceNum = numList.Sum(t => Mathf.Pow((t - averageNum), 2)) / numList.Count;

            return varianceNum;
        }

        /// <summary>
        /// 4D、获取 float链表 的 标准差
        /// </summary>
        /// <param name="numList">float 链表</param>
        /// <returns>标准差</returns>
        public static float GetStandardDeviationNum(this List<float> numList)
        {
            if (numList.IsNullOrCountZero())
                throw new Exception("numList is null or count is 0");

            var varianceNum = numList.GetVarianceNum();

            var standardDeviationNum = Mathf.Sqrt(varianceNum);

            return standardDeviationNum;
        }

        /// <summary>
        /// 5A、获取 float链表 最大值
        /// </summary>
        /// <param name="numList">float链表</param>
        /// <returns>最大值</returns>
        public static float GetMaxValueNum(this List<float> numList)
        {
            if (numList.IsNullOrCountZero())
                throw new Exception("numList is null or count is 0");

            return numList.Max();
        }

        /// <summary>
        /// 5B、获取 float链表 第一个最大值下标
        /// </summary>
        /// <param name="numList">float链表</param>
        /// <returns>第一个最大值下标</returns>
        public static int GetFirstMaxIndex(this List<float> numList)
        {
            if (numList.IsNullOrCountZero())
                throw new Exception("numList is null or count is 0");

            return numList.IndexOf(numList.Max());

            //var iPos = 0;
            //var value = numList[0];
            //for (var i = 0; i < numList.Count; i++)
            //{
            //    var num = numList[i];

            //    if (num.CompareTo(value) <= 0) continue;

            //    value = num;
            //    iPos = i;
            //}
            //return iPos;
        }

        /// <summary>
        /// 5C、获取 float链表 最后一个最大值下标
        /// </summary>
        /// <param name="numList">float链表</param>
        /// <returns>最后一个最大值下标</returns>
        public static int GetLastMaxIndex(this List<float> numList)
        {
            if (numList.IsNullOrCountZero())
                throw new Exception("numList is null or count is 0");

            return numList.LastIndexOf(numList.Max());

            //var iPos = 0;
            //var value = numList[0];
            //for (int i = 0; i < numList.Count; i++)
            //{
            //    var num = numList[i];

            //    if (num.CompareTo(value) < 0) continue;

            //    value = num;
            //    iPos = i;
            //}
            //return iPos;
        }

        /// <summary>
        /// 5D、获取 float链表 最小值
        /// </summary>
        /// <param name="numList">float链表</param>
        /// <returns>最小值</returns>
        public static float GetMinValueNum(this List<float> numList)
        {
            if (numList.IsNullOrCountZero())
                throw new Exception("numList is null or count is 0");
   
            return numList.Min();

            //var value = numList[0];
            //foreach (var _value in numList)
            //{
            //    if (_value.CompareTo(value) < 0)
            //    {
            //        value = _value;
            //    }
            //}
            //return value;
        }

        /// <summary>
        /// 5E、获取 float链表 第一个最小值下标
        /// </summary>
        /// <param name="numList">float链表</param>
        /// <returns>第一个最小值下标</returns>
        public static int GetFirstMinIndex(this List<float> numList)
        {
            if (numList.IsNullOrCountZero())
                throw new Exception("numList is null or count is 0");
            return numList.IndexOf(numList.Min());

            //var iPos = 0;
            //var value = numList[0];
             
            //for (var i = 0; i < numList.Count; i++)
            //{
            //    var num = numList[i];
            //    if (num.CompareTo(value) >= 0) continue;
            //    value = num;
            //    iPos = i;
            //}
            //return iPos;
        }

        /// <summary>
        /// 5F、获取 float链表 最后一个最小值下标
        /// </summary>
        /// <param name="numList">float链表</param>
        /// <returns>最后一个最小值下标</returns>
        public static int GetLastMinIndex(this List<float> numList)
        {
            if (numList.IsNullOrCountZero())
                throw new Exception("numList is null or count is 0");
            return numList.LastIndexOf(numList.Min());
            
            //var iPos = 0;
            //var value = numList[0];
            //for (int i = 0; i < numList.Count; i++)
            //{
            //    var num = numList[i];
            //    if (num.CompareTo(value) > 0) continue;
            //    value = num;
            //    iPos = i;
            //}
            //return iPos;
        }

        /// <summary>
        /// 6A、返回 字典 值对应的第一个索引
        /// </summary>
        /// <typeparam name="T1">字典索引类型</typeparam>
        /// <typeparam name="T2">字典值类型</typeparam>
        /// <param name="dict">字典</param>
        /// <param name="value">字典值</param>
        /// <returns>字典值对应的第一个索引</returns>
        public static T1 GetFirstKeyFromDictionaryWithValue<T1, T2>(this Dictionary<T1, T2> dict, T2 value)
        {
            if (dict.IsNullOrCountZero())
                throw new Exception("dict is null or count is zero");

            if (!dict.ContainsValue(value))
                throw new Exception("this dict values don't contains value");

            return dict.FirstOrDefault(q => q.Value.Equals(value)).Key;
        }

        /// <summary>
        /// 6B、返回 字典 值对应的最后一个索引
        /// </summary>
        /// <typeparam name="T1">字典索引类型</typeparam>
        /// <typeparam name="T2">字典值类型</typeparam>
        /// <param name="dict">字典</param>
        /// <param name="value">字典值</param>
        /// <returns>字典值对应的最后一个索引</returns>
        public static T1 GetLastKeyFromDictionaryWithValue<T1, T2>(this Dictionary<T1, T2> dict, T2 value)
        {
            if (dict.IsNullOrCountZero())
                throw new Exception("dict is null or count is zero");

            if (!dict.ContainsValue(value))
                throw new Exception("dict don't containsValue value");

            return dict.LastOrDefault(q => q.Value.Equals(value)).Key;
        }

        /// <summary>
        /// 6C、返回 字典 某下标对应的键值对
        /// </summary>
        /// <typeparam name="T1">字典 key 数据类型</typeparam>
        /// <typeparam name="T2">字典 value 数据类型</typeparam>
        /// <param name="dict">字典对象</param>
        /// <param name="index">下标</param>
        /// <returns>下标对应的键值对</returns>
        public static KeyValuePair<T1, T2> GetKeyValueFromDictionary<T1, T2>(this Dictionary<T1, T2> dict, int index)
        {
            if (dict.IsNullOrCountZero())
                throw new Exception("dict is null or count is zero");

            if (index >= dict.Count)
                throw new Exception("index exceeds the maximum value of the dict index");

            return dict.ElementAt(index);
        }

        /// <summary>
        /// 6D、返回 字典 某键对应的下标
        /// </summary>
        /// <typeparam name="T1">字典 key 数据类型</typeparam>
        /// <typeparam name="T2">字典 value 数据类型</typeparam>
        /// <param name="dict">字典对象</param>
        /// <param name="key">键</param>
        /// <returns>键对应的下标</returns>
        public static int GetKeyIndexFromDictionary<T1, T2>(this Dictionary<T1, T2> dict, T1 key)
        {
            if (dict.IsNullOrCountZero())
                throw new Exception("dict is null or count is zero");

            if (!dict.ContainsKey(key))
                throw new Exception("this dict does not contain this key");

            return (new List<T1>(dict.Keys)).IndexOf(key);
        }

        /// <summary>
        /// 7A、判断 链表对象元素 是否都为 目标元素
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="sequence">链表对象</param>
        /// <param name="t">目标元素</param>
        /// <returns>都为目标对象 True;<br/> 不都为目标对象 False;</returns>
        public static bool AllElementIsCertainValueInList<T>(this IEnumerable<T> sequence, T t)
        {
            var list = sequence.ToList();
            if (list.IsNullOrCountZero())
                throw new Exception("dict is null or count is zero");

            if (!list.Contains(t))
                throw new Exception("list don't contains t");

            return list.All(i => i.Equals(t));
        }

        /// <summary>
        /// 7B、返回 链表对象元素 组成的 字符串
        /// </summary>
        /// <typeparam name="T">链表数据类型</typeparam>
        /// <param name="sequence">链表对象</param>
        /// <param name="separator">连接字符</param>
        /// <returns></returns>
        public static string StringJoin<T>(this IEnumerable<T> sequence, string separator = " - ")
        {
            var list = sequence.ToList();
            if (list.IsNullOrCountZero())
                throw new Exception("list is null or count is zero");

            return string.Join(separator, list);
        }

        /// <summary>
        /// 7C、返回 指定链表对象 从开始下标到结束下标的元素组成的 新链表对象
        /// </summary>
        /// <typeparam name="T">链表数据类型</typeparam>
        /// <param name="sequence">链表对象</param>
        /// <param name="indexStart">开始下标</param>
        /// <param name="indexEnd">结束下标</param>
        /// <returns>该链表对象从开始下标到结束下标的元素组成的新链表对象</returns>
        public static List<T> GetListByIndexXToIndexY<T>(this IEnumerable<T> sequence, int indexStart, int indexEnd)
        {
            var list = sequence.ToList();
            if (list.IsNullOrCountZero())
                throw new Exception("list is null or count is zero");

            if (indexEnd > list.Count() - 1)
                throw new Exception("indexEnd exceeds the maximum value of the sequence index");

            if (indexEnd < indexStart)
                throw new Exception("indexEnd < indexStart");

            return new List<T>(list.Skip(indexStart).Take(indexEnd - indexStart + 1));
        }


        /// <summary>
        /// 8A、获取两点距离
        /// </summary>
        /// <param name="go1">对象1</param>
        /// <param name="go2">对象2</param>
        /// <returns></returns>
        public static float GetTheMagnitude(this GameObject go1, GameObject go2)
        {
            if (go1 == null || go2 == null)
                throw new Exception("GameObject is null");
            
            return (go1.transform.position - go2.transform.position).magnitude;
            
            //return Vector3.Distance(go1.transform.position, go2.transform.position);
        }

        /// <summary>
        /// 8B、弧度转角度
        /// </summary>
        /// <param name="angleRad">弧度</param>
        /// <returns></returns>
        public static float Radian2Degree(this float angleRad)
        {
            return angleRad * Mathf.Rad2Deg;
        }

        /// <summary>
        /// 8C、角度转弧度
        /// </summary>
        /// <param name="angleDeg">角度值</param>
        /// <returns></returns>
        public static float Degree2Radian(this float angleDeg)
        {
            return angleDeg * Mathf.Deg2Rad;
        }

        /// <summary>
        /// 8D、求两向量夹角(角度值)
        /// </summary>
        /// <param name="l1">向量1</param>
        /// <param name="r1">向量2</param>
        /// <returns>两向量夹角(角度值)</returns>
        public static float VecAngle(this Vector3 l1, Vector3 r1)
        {
            var lhs1 = l1.normalized; // 向量1单位向量  
            var rhs1 = r1.normalized; // 向量2单位向量  

            var dot = Vector3.Dot(lhs1, rhs1); // 使用Vector3.Dot计算点积
            var angleRad = Mathf.Acos(dot); // 获取弧度值  
            var angleDeg = angleRad.Radian2Degree(); // 将弧度转换为角度
            return angleDeg; // 返回角度值  
        }

        /// <summary>
        /// 8E、获取 向量l1 在 向量l2 的投影向量
        /// </summary>
        /// <param name="l1">向量 l1</param>
        /// <param name="l2">向量 l2</param>
        /// <returns>向量src 在 向量target 的投影向量</returns>
        public static Vector3 GetProjectVector(this Vector3 l1, Vector3 l2)
        {
            // 计算B的单位向量  
            var l2_unit = l2.normalized;
            // 计算A在B方向上的分量大小（即投影长度）  
            var projectionLength = Vector3.Dot(l1, l2);
            // 计算投影向量  
            return projectionLength * l2_unit;
        }

        /// <summary>
        /// 9A、二进制 转 十进制（string-->int）
        /// </summary>
        /// <param name="binaryStr"></param>
        /// <returns></returns>
        public static int Binary2DecimalNum(this string binaryStr)
        {
            var decimalNum = Convert.ToInt32(binaryStr, 2);
            return decimalNum;
        }

        /// <summary>
        /// 9B、二进制 转 十进制（string-->string）
        /// </summary>
        /// <param name="binaryStr"></param>
        /// <returns></returns>
        public static string Binary2DecimalStr(this string binaryStr)
        {
            var decimalStr = Binary2DecimalNum(binaryStr) + string.Empty;
            return decimalStr;
        }

        /// <summary>
        /// 9C、十进制 转 二进制（int-->string）
        /// </summary>
        /// <param name="decimalNum"></param>
        /// <returns></returns>
        public static string DecimalNum2Binary(this int decimalNum)
        {
            var binaryStr = Convert.ToString(decimalNum, 2);
            return binaryStr;
        }

        /// <summary>
        /// 9D、十进制 转 二进制（string-->string）
        /// </summary>
        /// <param name="decimalStr"></param>
        /// <returns></returns>
        public static string DecimalStr2Binary(this string decimalStr)
        {
            if (int.TryParse(decimalStr, out int decimalNum))
            {
                return DecimalNum2Binary(decimalNum);
            }

            throw new Exception("Num Conversion Is Fails");
        }

        /// <summary>
        /// 9E、十六进制 转 十进制（string-->int）
        /// </summary>
        /// <param name="hexStr"></param>
        /// <returns></returns>
        public static int Hex2DecimalNum(this string hexStr)
        {
            var decimalNum = Convert.ToInt32(hexStr, 16);
            return decimalNum;
        }

        /// <summary>
        /// 9F、十六进制 转 十进制（string-->string）
        /// </summary>
        /// <param name="hexStr"></param>
        /// <returns></returns>
        public static string Hex2DecimalStr(this string hexStr)
        {
            var decimalStr = Hex2DecimalNum(hexStr) + string.Empty;
            return decimalStr;
        }

        /// <summary>
        /// 9G、十进制 转 十六进制（Int-->string）
        /// </summary>
        /// <param name="decimalNum"></param>
        /// <returns></returns>
        public static string DecimalNum2Hex(this int decimalNum)
        {
            var hexStr = Convert.ToString(decimalNum, 16);
            return hexStr;
        }

        /// <summary>
        /// 9G+、十进制 转 十六进制（UInt-->string）
        /// </summary>
        /// <param name="decimalNum"></param>
        /// <returns></returns>
        public static string DecimalNum2Hex(this uint decimalNum)
        {
            var hexStr = Convert.ToString(decimalNum, 16);
            return hexStr;
        }

        /// <summary>
        /// 9H、十进制 转 十六进制（string-->string）
        /// </summary>
        /// <param name="decimalStr"></param>
        /// <returns></returns>
        public static string DecimalStr2Hex(this string decimalStr)
        {
            int.TryParse(decimalStr, out int decimalNum);
            var hexStr = DecimalNum2Hex(decimalNum);
            return hexStr;
        }

        /// <summary>
        /// 9I、十六进制 转 二进制（string-->string）
        /// </summary>
        /// <param name="hexStr"></param>
        /// <returns></returns>
        public static string Hex2Binary(this string hexStr)
        {
            //16->10 10->2
            var decimalNum = Hex2DecimalNum(hexStr);
            var binaryStr = DecimalNum2Binary(decimalNum);
            return binaryStr;
        }

        /// <summary>
        /// 9J、二进制 转 十六进制（string-->string）
        /// </summary>
        /// <param name="binaryStr"></param>
        /// <returns></returns>
        public static string Binary2HexStr(this string binaryStr)
        {
            //2->10 10->16
            var decimalNum = Binary2DecimalNum(binaryStr);
            var hexStr = DecimalNum2Hex(decimalNum);
            return hexStr;
        }

        /// <summary>
        /// 9K、返回1byte（2位16进制）二进制转换后的某一位
        /// </summary>
        /// <param name="c">byte数</param>
        /// <param name="index">目标位下标</param>
        /// <returns></returns>
        public static int GetBitFromByte2Binary(this byte c, int index)
        {
            int bit0 = (c & 1);
            int bit1 = ((c >> 1) & 1);
            int bit2 = ((c >> 2) & 1);
            int bit3 = ((c >> 3) & 1);
            int bit4 = ((c >> 4) & 1);
            int bit5 = ((c >> 5) & 1);
            int bit6 = ((c >> 6) & 1);
            int bit7 = ((c >> 7) & 1);

            switch (index)
            {
                case 0:
                    return bit0;
                case 1:
                    return bit1;
                case 2:
                    return bit2;
                case 3:
                    return bit3;
                case 4:
                    return bit4;
                case 5:
                    return bit5;
                case 6:
                    return bit6;
                case 7:
                    return bit7;
                default:
                    throw new IndexOutOfRangeException();
            }
        }

        /// <summary>
        /// 10A、将int值转换为枚举类型值
        /// </summary>
        /// <typeparam name="T">枚举类型</typeparam>
        /// <param name="value">int</param>
        /// <returns></returns>
        public static T GetEnumValueFromInt<T>(this int value) where T : Enum
        {
            if (!Enum.IsDefined(typeof(T), value))
            {
                throw new ArgumentException($"Value {value} is not a valid {typeof(T).Name} value.");
            }
            return (T)Enum.ToObject(typeof(T), value);
        }
    }


    /// <summary>
    /// MathLib 数学库 <br />
    /// /********************************** <br />
    /// 作用：<br />
    ///    01、Line 线 <br />
    ///    02、Plane 面 <br />
    ///    03、Triangle 三角形 <br />
    ///    04、Polygon 多边形 <br />
    ///    05、Sphere 球体 <br />
    /// 使用方法：<br />
    ///     1、引用命名空间，直接调用。<br />
    /// **********************************/ <br />
    /// </summary>
    public static class MathLib
    {
        /// <summary>
        /// 线
        /// </summary>
        public class Line
        {
            /// <summary>
            /// 线上的一点
            /// </summary>
            public Vector3 Point;

            /// <summary>
            /// 线的方向向量（应为单位向量）
            /// </summary>
            public Vector3 Direction;

            /// <summary>
            /// 线 构造器
            /// </summary>
            /// <param name="point">线上的一点</param>
            /// <param name="direction">线的方向向量（应为单位向量）</param>
            public Line(Vector3 point, Vector3 direction)
            {
                Point = point;
                Direction = direction.normalized; // 确保方向向量是单位向量 
            }

            /// <summary>
            ///  给定点到直线的最近点（3D）
            /// </summary>
            /// <param name="point">给定点</param>
            /// <returns></returns>
            public Vector3 GetClosestPoint(Vector3 point)
            {
                var projectionVector = (point - Point).GetProjectVector(Direction);
               
                return Point + projectionVector;
            }

            /// <summary>
            ///  给定点到直线的距离（3D）
            /// </summary>
            /// <param name="point">给定点</param>
            /// <returns></returns>
            public float GetDistanceOfPointToLine(Vector3 point)
            {
                var projectionVector = (point - Point).GetProjectVector(Direction);
                Vector3 target = Point + projectionVector;
                return (target - point).magnitude;
            }

            /// <summary>
            /// 判断两条线是否平行（3D）
            /// </summary>
            /// <param name="line1"></param>
            /// <param name="line2"></param>
            /// <returns></returns>
            public static bool IsParallel(Line line1, Line line2)
            {
                // 检查方向向量是否线性相关（即它们是平行的）  
                // 如果它们的叉积为零向量，则它们是平行的  
                Vector3 crossProduct = Vector3.Cross(line1.Direction, line2.Direction);
                // 使用叉积的模的平方来避免浮点数精度问题  
                return crossProduct.x * crossProduct.x + crossProduct.y * crossProduct.y + crossProduct.z * crossProduct.z < float.Epsilon;
            }

            /// <summary>
            ///  获取与直线方向垂直的向量（注意：这不是真正的法线，因为直线没有法线）  
            /// </summary>
            /// <returns></returns>
            public Vector3 GetPerpendicularVector()
            {
                // 假设Direction不是零向量  
                // 选择一个非零分量来构建叉积  
                if (Math.Abs(Direction.y) > float.Epsilon)
                {// 使用(1, 0, 0)与Direction进行叉积  
                    return Vector3.Cross(new Vector3(1, 0, 0), Direction).normalized;
                }

                if (Math.Abs(Direction.z) > float.Epsilon)
                {// 使用(0, 1, 0)与Direction进行叉积  
                    return Vector3.Cross(new Vector3(0, 1, 0), Direction).normalized;
                }
               
                // 使用(0, 0, 1)与Direction进行叉积  
                return Vector3.Cross(new Vector3(0, 0, 1), Direction).normalized;
            }
        }

        /// <summary>
        /// 面
        /// </summary>
        public class Plane
        {
            /// <summary>
            /// 平面上的一点
            /// </summary>
            public Vector3 planePoint;

            /// <summary>
            /// 单位法向量
            /// </summary>
            public Vector3 nitNormalVector;

            /// <summary>
            /// d值
            /// </summary>
            public float d;

            /// <summary>
            /// 平面 构造器  
            /// </summary>
            /// <param name="planePoint">平面上的一点</param>
            /// <param name="nitNormalVector">单位法向量</param>
            public Plane(Vector3 planePoint, Vector3 nitNormalVector)
            {
                this.planePoint = planePoint;
                this.nitNormalVector = nitNormalVector.normalized; // 确保法向量是单位向量  
                d = -Vector3.Dot(this.planePoint, this.nitNormalVector); // 注意这里取负值  
            }

            /// <summary>
            /// 单位法向量（只读属性）
            /// </summary>
            public Vector3 N => this.nitNormalVector;

            /// <summary>
            /// d值（只读属性）  
            /// </summary>
            public float D => this.d;

            /// <summary>
            /// 点到平面的距离
            /// </summary>
            /// <param name="point"></param>
            /// <returns></returns>
            public float DisPointToPlane(Vector3 point)
            {
                float distance = Vector3.Dot(point,nitNormalVector) - d;
                return Math.Abs(distance); // 距离 需要绝对值
            }

            /// <summary>
            /// 计算点集的最佳平面法向量  
            /// </summary>
            /// <param name="verts"></param>
            /// <returns></returns>
            public Vector3 ComputeBestFitNormal(Vector3[] verts)
            {
                Vector3 result = Vector3.zero;
                for (int i = 0; i < verts.Length - 1; i++)
                {
                    Vector3 p = verts[i];
                    Vector3 p1 = verts[i + 1];
                    result.x += (p.y * p1.z - p.z * p1.y); // 修正计算法向量的公式  
                    result.y += (p.z * p1.x - p.x * p1.z);
                    result.z += (p.x * p1.y - p.y * p1.x);
                }
                return result.normalized;
            }

            /// <summary>
            /// 计算点集最佳平面d值  
            /// </summary>
            /// <param name="verts"></param>
            /// <returns></returns>
            public float ComputeBestFitD(Vector3[] verts)
            {
                Vector3 n = ComputeBestFitNormal(verts);
                Vector3 p_sum = Vector3.zero;
                for (int i = 0; i < verts.Length; i++)
                {
                    p_sum += verts[i];
                }
                return -Vector3.Dot(p_sum / verts.Length, n); // 注意这里取负值  
            }

        }

        /// <summary>
        /// 三角形
        /// </summary>
        public class Triangle
        {
            /// <summary>
            /// 组成三角形的三个顶点的坐标
            /// </summary>
            public Vector3 p1, p2, p3;

            /// <summary>
            /// 组成三角形的三个边的长度
            /// </summary>
            float L1 => Vector3.Distance(p2, p3);
            /// <summary>
            /// 组成三角形的三个边的长度
            /// </summary>
            float L2 => Vector3.Distance(p3, p1);
            /// <summary>
            /// 组成三角形的三个边的长度
            /// </summary>
            float L3 => Vector3.Distance(p1, p2);

            /// <summary>
            /// 三角形 构造函数
            /// </summary>
            /// <param name="p1">顶点1</param>
            /// <param name="p2">顶点2</param>
            /// <param name="p3">顶点3</param>
            public Triangle(Vector3 p1, Vector3 p2, Vector3 p3)
            {
                this.p1 = p1;
                this.p2 = p2;
                this.p3 = p3;

                //检查三角不等式是否成立  
                if (TriangleInequality) return;

                this.p1 = Vector3.zero;
                this.p2 = Vector3.zero;
                this.p3 = Vector3.zero;
                throw new Exception("三顶点无法构成三角形（不满足三角不等式）");
            }

            /// <summary>
            /// 三角不等式
            /// </summary>
            public bool TriangleInequality => (L1 + L2 > L3) && (L1 + L3 > L2) && (L2 + L3 > L1);

            /// <summary>
            /// 法线向量
            /// </summary>
            public Vector3 Normal => Vector3.Cross(p2 - p1, p3 - p2).normalized;

            /// <summary>
            /// 周长
            /// </summary>
            public float Perimeter => L1 + L2 + L3;

            /// <summary>
            /// 半周长
            /// </summary>
            public float semiPerimeter => 0.5f * Perimeter;

            /// <summary>
            /// 面积（使用海伦公式）  
            /// </summary>
            public float AreaByHeronsFormula =>
            Mathf.Sqrt(semiPerimeter * (semiPerimeter - L1) * (semiPerimeter - L2) * (semiPerimeter - L3));

            /// <summary>
            /// 面积（使用叉乘）  
            /// </summary>
            public float AreaByCrossProduct => Vector3.Cross(p2 - p1, p3 - p1).magnitude * 0.5f; //s = |v1 x v2| * 0.5

            /// <summary>
            /// 质心（重心）  
            /// </summary>
            public Vector3 Centroid => (p1 + p2 + p3) / 3f;

            /// <summary>
            /// 计算内心到三边的距离（内切圆半径）= 三角形面积 / 周长
            /// </summary>
            public float IncircleRadius => AreaByHeronsFormula / Perimeter;

            /// <summary>
            /// 外接圆半径
            /// </summary>
            public float CircumcircleRadius => L1 * L2 * L3 / (4f * AreaByHeronsFormula);

            /// <summary>
            /// 判断点和三角形是否在同一平面上  
            /// </summary>
            /// <param name="point"></param>
            /// <returns></returns>
            public bool ArePointAndTriangleOnSamePlane(Vector3 point)
            {
                // 平面方程 Ax + By + Cz + D = 0  
                // 已知平面上的一个点 planePoint 和平面的法线 planeNormal  
                // 可以得到 D = - (Ax0 + By0 + Cz0)  
                // 点到平面的距离公式为 |Ax + By + Cz + D| / sqrt(A^2 + B^2 + C^2)  
                var d = -Vector3.Dot(Normal, p1);
                float distance = Vector3.Dot(Normal, point) + d;
                // 检查点到平面的距离是否在给定的容差范围内  
                return Mathf.Abs(distance) <= 0.0001f;
            }

            /// <summary>
            /// 判断点是否在三角形内部（重心法）
            /// </summary>
            /// <param name="point"></param>
            /// <returns></returns>
            public bool IsPointInTriangle(Vector3 point)
            {
                if (!ArePointAndTriangleOnSamePlane(point))
                    throw new Exception("点与三角形不在同一平面上！");

                //P = A +  u * (C – A) + v * (B - A)
                // 计算三角形的向量  
                Vector3 v0 = p2 - p1;
                Vector3 v1 = p3 - p1;
                Vector3 v2 = point - p1;

                // 计算点积  
                float dot00 = Vector3.Dot(v0, v0);
                float dot01 = Vector3.Dot(v0, v1);
                float dot02 = Vector3.Dot(v0, v2);
                float dot11 = Vector3.Dot(v1, v1);
                float dot12 = Vector3.Dot(v1, v2);

                // 计算行列式  
                float invDenom = 1.0f / (dot00 * dot11 - dot01 * dot01);
                float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
                float v = (dot00 * dot12 - dot01 * dot02) * invDenom;

                // 检查重心坐标是否在三角形内  
                return (u >= 0) && (v >= 0) && (u + v < 1);
            }
        }

        /// <summary>
        /// 多边形
        /// </summary>
        public class Polygon
        {
            /// <summary>
            /// 顶点
            /// </summary>
            public Vector3[] vertexs;

            /// <summary>
            /// 多边形 构造器
            /// </summary>
            /// <param name="vertexs">顶点</param>
            public Polygon(params Vector3[] vertexs)
            {
                this.vertexs = vertexs;
            }

            /// <summary>
            /// 是否为凸多边形
            /// </summary>
            public bool IsConvex
            {
                get
                {
                    for (int i = 0; i < vertexs.Length; i++)
                    {
                        int nextIndex = (i + 1) % vertexs.Length; // 循环回到开始  
                        Vector3 edge0 = vertexs[i] - vertexs[i == 0 ? vertexs.Length - 1 : i - 1];
                        Vector3 edge1 = vertexs[nextIndex] - vertexs[i];

                        // 使用叉积判断两条边是否在同一侧（即夹角小于180度）  
                        Vector3 cross = Vector3.Cross(edge0, edge1);

                        // 如果叉积的z分量（假设z轴为垂直于平面的方向）小于0，则表示存在凹口  
                        if (cross.z < 0f)
                        {
                            return false; // 不是凸多边形  
                        }
                    }
                    return true; // 所有边都在同一侧，是凸多边形  
                }
            }
        }

        /// <summary>
        /// 球体
        /// </summary>
        public class Sphere
        {
            /// <summary>
            /// 球心坐标
            /// </summary>
            public Vector3 Center { get; }
            
            /// <summary>
            /// 球半径
            /// </summary>
            public float Radius { get; }

            /// <summary>
            /// 球 构造器
            /// </summary>
            /// <param name="center">球心坐标</param>
            /// <param name="radius">球半径</param>
            public Sphere(Vector3 center, float radius)
            {
                Center = center;
                Radius = radius;
            }

            /// <summary>
            /// 点与球的位置关系枚举
            /// </summary>
            public enum PointSphereRelation
            {
                InTheSphere,
                OnTheSphere,
                OutSideTheSphere
            }

            /// <summary>
            /// 点 与 球体关系
            /// </summary>
            /// <param name="point">点</param>
            /// <returns></returns>
            public PointSphereRelation PointInOrOnOrOutSideTheSphere(Vector3 point)
            {
                if ((Center - point).magnitude - Radius < 0)
                {
                    return PointSphereRelation.InTheSphere;
                }

                if ((Center - point).magnitude - Radius == 0)
                {
                    return PointSphereRelation.OnTheSphere;
                }

                return PointSphereRelation.OutSideTheSphere;

            }

            /// <summary>
            /// 返回球面上离给定点p最近的点
            /// </summary>
            /// <param name="point"></param>
            /// <returns></returns>
            public Vector3 GetClosestPoint(Vector3 point)
            {
                var d = Center - point;//point 指向 center 向量

                if (d.magnitude == 0)
                    throw new Exception("该点所在位置为球心！");

                return Center - d.normalized * Radius;
            }

            /// <summary>
            /// 射线与球的交点
            /// </summary>
            /// <param name="ray">射线</param>
            /// <param name="IsIntersect"></param>
            /// <returns></returns>
            public Vector3[] GetIntersectPoints(Ray ray, out bool IsIntersect)
            {
                IsIntersect = false;

                Vector3 oc = Center - ray.origin;//射线起点到球心的向量

                // a = direction.dot(direction)  
                float a = Vector3.Dot(ray.direction, ray.direction);

                // b = 2 * direction.dot(oc)  
                float b = 2f * Vector3.Dot(ray.direction, oc);

                // c = oc.dot(oc) - radius * radius  
                float c = Vector3.Dot(oc, oc) - Radius * Radius;

                // 计算判别式  
                float discriminant = b * b - 4 * a * c;

                // 如果判别式小于0，则射线与球不相交  
                if (discriminant < 0)
                {
                    return Array.Empty<Vector3>(); // 返回空数组表示没有交点  
                }

                // 否则，计算两个交点的距离  
                float t0, t1;

                // 如果判别式等于0，则射线与球相切于一个点  
                if (discriminant == 0)
                {
                    t0 = t1 = -b / (2f * a);
                }
                // 否则，射线与球相交于两个点  
                else
                {
                    // 计算两个解  
                    float sqrtD = (float)Math.Sqrt(discriminant);
                    t0 = (-b - sqrtD) / (2f * a);
                    t1 = (-b + sqrtD) / (2f * a);

                    // 确保t0是较小的解（即射线先碰到的点）  
                    if (t0 > t1)
                    {
                        (t0, t1) = (t1, t0);
                    }

                    // 如果t0是负数，表示射线从球内部发出，我们只关心t1（外部交点）  
                    if (t0 < 0)
                    {
                        t0 = t1;
                        // 如果t1也是负数，表示射线在球内部，没有外部交点  
                        if (t1 < 0)
                        {
                            return Array.Empty<Vector3>();
                        }
                    }
                }

                // 计算交点  
                Vector3 p0 = ray.origin + t0 * ray.direction;
                Vector3 p1 = ray.origin + t1 * ray.direction;

                // 返回交点数组  
                return new[] { p0, p1 };
            }
        }
    }
}
